#include"myshell.h"
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<string>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>


char* gargv[ARGS] = { 0 };
int gargc = 0;
char pwd[1024];
int lastcode = 0;

#define NONE_REDIR 0
#define OUTPUT_REDIR 1
#define INPUT_REDIR 2
#define APPEND_REDIR 3

std::string filename;
int redir_type = NONE_REDIR;

#define SkipSpace(start) while(*start == ' ')\
                        {\
                            start++;\
                        }


//void Debug()
//{
//    printf("hello world\n");
//}

static std::string GetUserName()
{
    std::string user_name = getenv("USER");
    return user_name.empty() ? std::string() : user_name;
}

static std::string GetHostName()
{
    std::string host_name = getenv("HOSTNAME");
    return host_name.empty() ? std::string() : host_name;
}

static std::string GetPwd()
{
    //std::string pwd = getenv("PWD");
    //return pwd.empty() ? std::string() : pwd;
    char temp[1024];
    getcwd(temp, sizeof(temp));
    snprintf(pwd, sizeof(pwd), "PWD=%s", temp);
    putenv(pwd);
    std::string pwd_lable = temp;
    size_t pos = pwd_lable.rfind("/");
    pwd_lable = pwd_lable.substr(pos + 1);
    return pwd_lable.empty() ? "/" : pwd_lable;
}

static std::string GetHomePath()
{
    std::string home_path = getenv("HOME");
    return home_path.empty() ? std::string() : home_path;
}

void PrintCommandPrompt()
{
    std::string user_name = GetUserName();
    std::string host_name = GetHostName();
    std::string pwd = GetPwd();
    std::cout << "[" << user_name << "@" << host_name << " " << pwd << "]$ ";
}

bool GetCommandString(char cmd_str_buff[], int len)
{
    if(cmd_str_buff == NULL || len <= 0)
    {
        return false;
    }
    char* ret = fgets(cmd_str_buff, len, stdin);
    if(ret == NULL)
    {
        return false;
    }
    cmd_str_buff[strlen(cmd_str_buff) - 1] = 0;
    return strlen(cmd_str_buff) == 0 ? false : true;
}

bool ParseCommandString(char cmd_str[])
{
    if(cmd_str == NULL)
    {
        return false;
    }
    gargv[gargc] = strtok(cmd_str, " ");
    while(gargv[gargc] != NULL)
    {
        gargv[++gargc] = strtok(NULL, " ");
    }
    //printf("%d\n", gargc);
    //for(int i = 0; i < gargc; i++)
    //{
    //    printf("gargv[%d] = %s\n", i, gargv[i]);
    //}
    //printf("\n");
    //for(int i = 0; gargv[i]; i++)
    //{
    //    printf("gargv[%d] = %s\n", i, gargv[i]);
    //}
    return true;
}

void InitCommandString()
{
    gargc = 0;
    memset(gargv, 0, sizeof(gargv));
    filename.clear();
    redir_type = NONE_REDIR;
}

void CheckRedir(char cmd[])
{
    char* start = cmd;
    char* end = cmd + strlen(cmd) - 1;
    while(start <= end)
    {
        if(*start == '>')
        {
            if(*(start + 1) == '>')
            {
                //ls -l > log.txt
                redir_type = APPEND_REDIR;
                *start = '\0';
                start += 2;
                SkipSpace(start);
                filename = start;
                break;
            }
            else
            {
                redir_type = OUTPUT_REDIR;
                *start = '\0';
                start++;
                SkipSpace(start);
                filename = start;
                break;
            }
        }
        else if(*start == '<')
        {
            redir_type = INPUT_REDIR;
            *start = '\0';
            start++;
            SkipSpace(start);
            filename = start;
            break;
        }
        else
        {
            start++;
        }
    }
}

void ForkExec()
{
    pid_t pid = fork();
    if(pid < 0)
    {
        perror("fork");
        return;
    }
    else if(pid == 0)
    {
        //子进程
        if(redir_type == OUTPUT_REDIR)
        {
            int fd_output = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
            if(fd_output < 0)
            {
                perror("open");
                printf("输出重定向出错！\n");
            }
            dup2(fd_output, 1);
        }
        else if(redir_type == INPUT_REDIR)
        {
            int fd_input = open(filename.c_str(), O_RDONLY);
            if(fd_input < 0)
            {
                perror("open");
                printf("输入重定向出错！\n");
            }
            dup2(fd_input, 0);
        }
        else if(redir_type == APPEND_REDIR)
        {
            int fd_append = open(filename.c_str(), O_WRONLY | O_CREAT | O_APPEND);
            if(fd_append < 0)
            {
                perror("open");
                printf("追加重定向出错！\n");
            }
            dup2(fd_append, 1);
        }
        execvp(gargv[0], gargv); 
        exit(0);
    }
    else
    {
        //父进程
        int status = 0;
        pid_t ret = waitpid(pid, &status, 0);
        if(ret > 0)
        {
            lastcode = WEXITSTATUS(status); 
        }
    }
}

bool BuiltInCommandExec()
{
    std::string cmd = gargv[0];
    bool val = false;
    if(cmd == "cd")
    {
        if(gargc == 2)
        {
            std::string target = gargv[1];
            if(target == "~")
            {
                val = true;
                chdir(GetHomePath().c_str());
            }
            else
            {
                val = true;
                chdir(gargv[1]);
            }
        }
        else if(gargc == 1)
        {
            val = true;
            chdir(GetHomePath().c_str());
        }
        else
        {

        }
    }
    else if(cmd == "echo")
    {
        if(gargc == 2)
        {
            std::string target = gargv[1];
            if(target[0] == '$')
            {
                if(target[1] == '?')
                {
                    val = true;
                    printf("lastcode:%d\n", lastcode);
                    lastcode = 0;
                }
                else
                {
                    val = true;
                    const char* myenv = &target[1];
                    printf("%s\n", getenv(myenv));
                    lastcode = 0;
                }
            }
            else
            {
                val = true;
                std::cout << target << std::endl;
            }
        }
    }
    return val;
}










